import { defineStore } from "pinia";
import { getToken, removeToken, setToken } from "../utils/token-utils";
import { allAsyncRoutes, anyRoutes, staticRoutes } from "@/router/routes";

// 类型
import type { UserInfoState } from "./interface";
import type { RequestLoginParamsType } from "@/api/user/interface";

// 接口
import { requestLogin, requestUserInfo, requestLogout } from "@/api/user";
import type { RouteRecordRaw } from "vue-router";
import router from "@/router";
import { cloneDeep } from "lodash";

/**
 * 用户信息
 * @methods initUserInfo 初始化用户信息
 */
function initUserInfo() {
  return {
    routes: [],
    buttons: [],
    roles: [],
    name: "",
    avatar: "",
  };
}

/**
 * 根据用户返回的权限信息，过滤动态路由
 */
function filterAsyncRoutes(
  allAsyncRoutes: RouteRecordRaw[],
  userRightRoutes: string[]
) {
  return allAsyncRoutes.filter((item) => {
    // 判断当前路由是否，在用户路由的权限中
    if (userRightRoutes.includes(item.name as string)) {
      // 递归过滤子级路由
      if (item.children && item.children.length) {
        item.children = filterAsyncRoutes(item.children, userRightRoutes);
      }
      return true;
    }
  });
}

/**
 *
 * @param userAsyncRoutes 用户权限路由
 */
function addRoutes(userAsyncRoutes: RouteRecordRaw[]) {
  userAsyncRoutes.forEach((item) => {
    router.addRoute(item);
  });
}

/**
 * 重置路由(将路由重置为初始的静态路由)
 */
function resetRoutes() {
  // 得到所有的注册路由
  const allReadyRoutes = router.getRoutes();
  // 先删除所有的路由(含有 name)
  allReadyRoutes.forEach((item) => {
    if (item.name) {
      router.removeRoute(item.name);
    }
  });
  // 再将所有的静态路由添加进去
  addRoutes(staticRoutes);
}

/**
 * 用户信息
 * @methods setUserInfos 设置用户信息
 */
export const useUserInfoStore = defineStore("userInfo", {
  state: (): UserInfoState => ({
    token: getToken() as string,
    userInfo: initUserInfo(),
    // 静态路由
    menuRoutes: staticRoutes,
  }),

  actions: {
    async loginAction(loginAction: RequestLoginParamsType) {
      try {
        const { token } = await requestLogin(loginAction);
        // 将 token 保存
        this.token = token;
        // 将 token 存储到 localStorage 中
        setToken(token);
      } catch (error) {
        return Promise.reject(error);
      }
    },

    async userInfoAction() {
      try {
        this.userInfo = await requestUserInfo();
        // 调用过滤动态路由函数
        const userAsyncRoutes = filterAsyncRoutes(
          cloneDeep(allAsyncRoutes), // 将原来的动态路由的数据进行深拷贝，防止改动原来的数据，造成动态路由丢失
          this.userInfo.routes
        );
        // 调用添加动态路由的方法（此时路由已经在项目中注册，所以使用 router.addRuote 方法动态添加路由，addRoute 一次只能添加一个路由，所以我们封装一个函数）
        addRoutes([...userAsyncRoutes, anyRoutes]); // 将任意路由和用户动态路由合并，一同添加到路由中
        // 此时动态路由已经添加完毕，但是菜单栏是由静态路（menuRoutes: staticRoutes）由生成的，所以我们还要修改 menuRoutes 来改变菜单栏
        this.menuRoutes = [...staticRoutes, ...userAsyncRoutes];
      } catch (error) {
        return Promise.reject(error);
      }
    },

    async logoutAction() {
      try {
        await requestLogout();
        this.resetAction();
        // 调用重置路由的方法(当我们从权限高的账户切换到低的，菜单发生了改变，但是原来限高的账户的路由还在，我们直接可以通过地址栏访问，这样就有些不妥，所以在退出登录的时候我们将路由重置为之前的静态路由)
        resetRoutes();
      } catch (error) {
        return Promise.reject(error);
      }
    },

    //路由守卫当中获取用户信息失败的时候,我们需要重置token和用户信息,重新跳转登录页
    resetAction() {
      // 删除local中保存的token
      removeToken();
      // 清除 pinia 中的用户数据
      (this.token = ""), (this.userInfo = initUserInfo());
    },
  },
});
